package stdx;

import java.io.*;
import java.io.File;
import java.util.*;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class Utils{
	private static String charset = null;
	private static boolean islinux = System.getProperty("os.name").toUpperCase().indexOf("WINDOW") < 0;

	static{
		String path = null;
		String lang = System.getenv("LANG");

		if (lang == null || lang.toUpperCase().indexOf("GBK") < 0){
			charset = "UTF-8";
		}
		else{
			charset = "GBK";
		}

		islinux = System.getProperty("os.name").toUpperCase().indexOf("WINDOW") < 0;

		if (islinux){
			path = Utils.Translate("$CPPWEB_INSTALL_HOME/product");
		}
		else{
			path = Utils.Translate("$CPPWEB_INSTALL_HOME/product/win");
		}

		String jnipath = path + "/dll/libjni.stdx.so";

		if (new File(jnipath).isFile()) System.load(jnipath);
	}

	public native static String GetEnv(String key);
	public native static String SetEnv(String key, String val);

	public native static String GetConfigFilePath();
	public native static int LoadConfig(String path);
	public native static String GetConfig(String path);

	public static boolean IsLinux(){
		return islinux;
	}
	public static byte[] Run(String cmd){
		int sz = 0;
		byte[] res = new byte[1024 * 1024];

		InputStream file = null;
		java.lang.Process proc = null;

		try{
			if (Utils.IsLinux()){
				String[] args = {"sh", "-c", cmd};
				proc = Runtime.getRuntime().exec(args);
			}
			else{
				String[] args = {"cmd", "/c", cmd};
				proc = Runtime.getRuntime().exec(args);
			}

			proc.waitFor();
			file = proc.getInputStream();

			if ((sz = file.read(res)) < res.length){
				byte[] tmp = new byte[sz];

				System.arraycopy(res, 0, tmp, 0, sz);
				res = tmp;
			}
		}
		catch(Exception e){
			res = null;
		}
		finally{
			Utils.Close(file);
		}

		return res;
	}
	public static void Sleep(long millis){
		try {
			Thread.sleep(millis);
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
	public static String GetCurrentPath(){
		return System.getProperty("user.dir").replaceAll("\\\\", "/");
	}
	public static String GetLocalCharset(){
		return charset;
	}
	public static String Translate(String msg){
		byte[] res = null;

		if (Utils.IsLinux()) {
			if (msg.indexOf('$') < 0 && msg.indexOf('`') < 0) return msg;

			res = Run("echo " + msg);
		}
		else{
			if (msg.indexOf('$') < 0){
				if (msg.indexOf('%') < 0) return msg;
			}
			else{
				String tmp = "";
				String[] vec = msg.split("/");

				for (String item : vec) {
					tmp += "/";

					int pos = item.indexOf('$');
					
					if (pos < 0){
						tmp += item;
					}
					else{
						if (pos > 0) tmp += item.substring(0, pos);

						item = item.substring(pos + 1);

						if (item.length() > 2){
							if (item.charAt(0) == '{') item = item.substring(0, item.length() - 2);
							if (item.charAt(0) == '(') item = item.substring(0, item.length() - 2);
						}

						tmp += "%" + item + "%";
					}
				}

				if (msg.endsWith("/")){
					msg = tmp.substring(1) + "/";
				}
				else {
					msg = tmp.substring(1);
				}
			}

			res = Run("echo " + msg);
		}

		if (res == null) return msg;

		try{
			msg = new String(res, Utils.GetLocalCharset()).trim();
		}
		catch(Exception e){
			e.printStackTrace();
		}

		return msg;
	}

	public static void Close(Closeable obj){
		try{
			obj.close();
		}
		catch(Exception e){
		}
	}
	public static void Close(AutoCloseable obj){
		try{
			obj.close();
		}
		catch(Exception e){
		}
	}
	public static String GetStackString(Throwable error){
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		PrintWriter writer = new PrintWriter(output, true);
		try {
			error.printStackTrace(writer);
			return output.toString().trim();
		}
		finally{
			Close(writer);
			Close(output);
		}
	}

	public static boolean IsEmpty(Object obj){
		if (obj == null) return true;
		if (obj instanceof String) return ((String)(obj)).isEmpty();
		if (obj instanceof Collection) return ((Collection)(obj)).isEmpty();
		if (obj instanceof Map) return ((Map)(obj)).isEmpty();
		if (obj instanceof Set) return ((Set)(obj)).isEmpty();
		return false;
	}
	public static boolean IsNotEmpty(Object obj){
		return !IsEmpty(obj);
	}
	public static boolean IsAlphaString(String str){
		if (str == null || str.isEmpty()) return false;

		for (int i = 0; i < str.length(); i++){
			char ch = str.charAt(i);

			if (ch < 'A' || ch > 'z') return false;
			if (ch > 'Z' && ch < 'a') return false;
		}

		return true;
	}
	public static boolean IsAlnumString(String str){
		if (str == null || str.isEmpty()) return false;

		for (int i = 0; i < str.length(); i++){
			char ch = str.charAt(i);

			if (ch < '0' || ch > 'z') return false;
			if (ch > '9' && ch < 'A') return false;
			if (ch > 'Z' && ch < 'a') return false;
		}

		return true;
	}
	public static boolean IsNumberString(String str){
		if (str == null || str.isEmpty()) return false;

		for (int i = 0; i < str.length(); i++){
			char ch = str.charAt(i);

			if (ch < '0' || ch > '9') return false;
		}

		return true;
	}
	public static boolean IsAmountString(String str){
		if (str == null || str.isEmpty()) return false;

		try{
			Double.parseDouble(str);
			return true;
		}
		catch(Exception e){
			return false;
		}
	}

	public static List<String> Split(String str){
		List<String> list = new ArrayList<>();
		if (IsEmpty(str)) return list;
		String[] arr = str.split(",");
		for (int i = 0; i < arr.length; i++){
			list.add(arr[i]);
		}
		return list;
	}
	public static List<Long> SplitLong(String str){
		List<Long> list = new ArrayList<>();
		if (IsEmpty(str)) return list;
		String[] arr = str.split(",");
		for (int i = 0; i < arr.length; i++){
			list.add(Long.parseLong(arr[i].trim()));
		}
		return list;
	}
	public static List<Integer> SplitInt(String str){
		List<Integer> list = new ArrayList<>();
		if (IsEmpty(str)) return list;
		String[] arr = str.split(",");
		for (int i = 0; i < arr.length; i++){
			list.add(Integer.parseInt(arr[i].trim()));
		}
		return list;
	}
	public static List<String> Split(String str, String spliter){
		List<String> list = new ArrayList<>();
		if (IsEmpty(str)) return list;
		String[] arr = str.split(spliter);
		for (int i = 0; i < arr.length; i++){
			list.add(arr[i].trim());
		}
		return list;
	}
	public static List<Long> SplitLong(String str, String spliter){
		String[] arr = str.split(spliter);
		List<Long> list = new ArrayList<>();
		for (int i = 0; i < arr.length; i++){
			list.add(Long.parseLong(arr[i].trim()));
		}
		return list;
	}
	public static List<Integer> SplitInt(String str, String spliter){
		String[] arr = str.split(spliter);
		List<Integer> list = new ArrayList<>();
		for (int i = 0; i < arr.length; i++){
			list.add(Integer.parseInt(arr[i].trim()));
		}
		return list;
	}

	public static String Join(String tag, int len){
		return Join(tag, len, ",");
	}
	public static <T> String Join(Collection<T> idset){
		return Join(idset, ",");
	}
	public static String Join(String tag, int len, String spliter){
		String res = "";
		while (len-- > 0){
			res += spliter + tag;
		}
		return res.isEmpty() ? res : res.substring(spliter.length());
	}
	public static <T> String Join(Collection<T> idset, String spliter){
		String res = "";
		for (Object item : idset){
			res += spliter + item.toString();
		}
		return res.isEmpty() ? res : res.substring(spliter.length());
	}

	public static String GetDateTimeString(){
		return GetDateTimeString(new Date());
	}
	public static String GetDateTimeSequence(){
		return GetDateTimeSequence(new Date());
	}
	public static String GetDateTimeString(Date date){
		return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
	}
	public static String GetDateTimeSequence(Date date){
		return new SimpleDateFormat("yyyyMMddHHmmss").format(date);
	}
	public static Date DateFromString(String str) throws ParseException{
		if (IsEmpty(str)) return null;
		if (str.length() > 19) str = str.substring(0, 19);
		switch (str.length()){
			case 8: return new SimpleDateFormat("yyyyMMdd").parse(str);
			case 10: return new SimpleDateFormat("yyyy-MM-dd").parse(str);
			case 14: return new SimpleDateFormat("yyyyMMddHHmmss").parse(str);
			case 16: return new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(str);
			default: return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(str);
		}
	}

	public static long GetFileLength(String path){
		File file = new File(path);
		return file.isFile() ? file.length() : BaseException.ERROR.getErrorCode();
	}
	public static List<File> GetFolderContent(String path) throws Exception{
		return GetFolderContent(path, 8);
	}
	public static List<File> GetFolderContent(String path, int depth) throws Exception{
		List<File> res = new ArrayList<File>();
		if (depth <= 0) return res;

		File dir = new File(path);
		File[] arr = dir.listFiles();
		if (arr == null) return res;

		for (int i = 0; i < arr.length; i++) {
			File file = arr[i];

			if (file.isFile()){
				res.add(file);
				continue;
			}

			if (file.isDirectory()){
				res.addAll(GetFolderContent(file.getAbsolutePath(), depth - 1));
			}
		}

		return res;
	}
	public static String GetFileString(String path) throws IOException, FileNotFoundException{
		String res = null;
		byte[] content = GetFileContent(path);

		try{
			res = new String(content, GetLocalCharset());
		}
		catch(Exception e){
			e.printStackTrace();
		}

		return res;
	}
	public static byte[] GetFileContent(String path) throws IOException, FileNotFoundException{
		byte[] content = null;
		long len = GetFileLength(path);

		if (len <= 0 || len > 64 * 1024 * 1024) return content;

		FileInputStream file = null;

		try{
			file = new FileInputStream(path);
			content = new byte[(int)(len)];
			file.read(content);
		}
		finally{
			Utils.Close(file);
		}

		return content;
	}
	public static void SetFileContent(String path, byte[] content) throws IOException, FileNotFoundException{
		FileOutputStream file = null;

		try{
			file = new FileOutputStream(path);
			file.write(content);
			file.flush();
		}
		finally{
			Utils.Close(file);
		}
	}

	public static String GetResourceString(Class clazz, String path) throws IOException{
		String res = null;
		byte[] content = GetResourceContent(clazz, path);

		if (content == null) return null;

		try{
			res = new String(content, GetLocalCharset());
		}
		catch(Exception e){
			e.printStackTrace();
		}

		return res;
	}
	public static byte[] GetResourceContent(Class clazz, String path) throws IOException{
		if (clazz == null) clazz = Utils.class;

		InputStream file = clazz.getResourceAsStream(path);

		if (file == null) return null;

		try{
			byte[] buffer = new byte[file.available()];
			file.read(buffer);
			return buffer;
		}
		finally{
			Utils.Close(file);
		}
	}

	@SuppressWarnings("unchecked")
	public static <T> T GetSimpleObject(Class<T> clazz, String val){
		if (clazz == String.class) return (T)(val == null ? "" : val);

		if (val == null || val.isEmpty()) val = "0";

		if (clazz == Byte.class) return (T)Byte.valueOf(Byte.parseByte(val));
		if (clazz == Long.class) return (T)Long.valueOf(Long.parseLong(val));
		if (clazz == Short.class) return (T)Short.valueOf(Short.parseShort(val));
		if (clazz == Float.class) return (T)Float.valueOf(Float.parseFloat(val));
		if (clazz == Double.class) return (T)Double.valueOf(Double.parseDouble(val));
		if (clazz == Integer.class) return (T)Integer.valueOf(Integer.parseInt(val));
		if (clazz == Boolean.class) return (T)Boolean.valueOf(val.equalsIgnoreCase("true"));

		return null;
	}
	public static <T> String GetFieldString(Class<T> clazz) throws IllegalAccessException{
		return GetFieldString(clazz, null, null);
	}
	public static <T> String GetFieldString(Class<T> clazz, String exlist) throws IllegalAccessException{
		return GetFieldString(clazz, exlist, null);
	}
	public static <T> String GetFieldString(Class<T> clazz, String exlist, String prefix) throws IllegalAccessException{
		String res = "";
		Field[] fields = clazz.getFields();

		exlist = "," + exlist + ",";

		if (prefix == null || prefix.isEmpty()){
			for (Field field : fields){
				String type = "," + field.getName() + ",";
				if (exlist.indexOf(type) >= 0) continue;
				res += "," + field.getName();
			}
		}
		else{
			for (Field field : fields){
				String type = "," + field.getName() + ",";
				if (exlist.indexOf(type) >= 0) continue;
				res += "," + prefix + field.getName();
			}
		}

		return res.substring(1);
	}
	public static void InitFieldValue(Field field, Object obj, String val) throws ParseException, IllegalAccessException{
		String type = field.getGenericType().toString();

		field.setAccessible(true);

		if (val == null || val.isEmpty()){
			if (type.length() >= 8){
				field.set(obj, type.equals("class java.lang.String") ? val : null);
			}
		}
		else{
			switch (type){
				case "int":
					field.setInt(obj, Integer.valueOf(Integer.parseInt(val)));
					break;
				case "byte":
					field.setByte(obj, Byte.valueOf(Byte.parseByte(val)));
					break;
				case "char":
					field.setChar(obj, val.charAt(0));
					break;
				case "long":
					field.setLong(obj, Long.valueOf(Long.parseLong(val)));
					break;
				case "short":
					field.setShort(obj, Short.valueOf(Short.parseShort(val)));
					break;
				case "float":
					field.setFloat(obj, Float.valueOf(Float.parseFloat(val)));
					break;
				case "double":
					field.setDouble(obj, Double.valueOf(Double.parseDouble(val)));
					break;
				case "boolean":
					field.setBoolean(obj, Boolean.valueOf(Boolean.parseBoolean(val)));
					break;
				case "class java.util.Date":
					field.set(obj, DateFromString(val));
					break;
				case "class java.lang.Long":
					field.set(obj, Long.valueOf(Long.parseLong(val)));
					break;
				case "class java.lang.Byte":
					field.set(obj, Byte.valueOf(Byte.parseByte(val)));
					break;
				case "class java.lang.Short":
					field.set(obj, Short.valueOf(Short.parseShort(val)));
					break;
				case "class java.lang.Float":
					field.set(obj, Float.valueOf(Float.parseFloat(val)));
					break;
				case "class java.lang.String":
					field.set(obj, val);
					break;
				case "class java.lang.Double":
					field.set(obj, Double.valueOf(Double.parseDouble(val)));
					break;
				case "class java.lang.Integer":
					field.set(obj, Integer.valueOf(Integer.parseInt(val)));
					break;
				case "class java.lang.Boolean":
					field.set(obj, Boolean.valueOf(Boolean.parseBoolean(val)));
					break;
				case "class java.lang.Character":
					field.set(obj, Character.valueOf(val.charAt(0)));
					break;
			}
		}
	}
}